﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using WarioOldies.Models;
using System.IO;
using System.Diagnostics;

namespace GameListCreator.ViewModels
{
    public class GameListViewModel : ViewModel
    {
        public GameListViewModel()
        {
            ObservableCollection<string> genres = new ObservableCollection<string>();

            genres.Add("Unclassified");
            genres.Add("Action");
            genres.Add("Adventure");
            genres.Add("Arcade");
            genres.Add("Board");
            genres.Add("Game");
            genres.Add("Card");
            genres.Add("Casino");
            genres.Add("Educational");
            genres.Add("Fighter");
            genres.Add("Maze");
            genres.Add("Pinball");
            genres.Add("Platform");
            genres.Add("Puzzle");
            genres.Add("Racing");
            genres.Add("RPG");
            genres.Add("Shooter");
            genres.Add("Simulation");
            genres.Add("Sports");
            genres.Add("Strategy");
            genres.Add("Word");

            this.Genres = genres;
        }

        /// <summary>
        /// Nom de la propriété Genres
        /// </summary>

        public const string GenresPropertyName = "Genres";

        /// <summary>
        /// propriété Genres :  
        /// </summary>

        public ObservableCollection<string> Genres
        {
            get
            {
                return this._Genres;
            }

            private set
            {
                if (this._Genres != value)
                {
                    this._Genres = value;
                    this.RaisePropertyChanged(GenresPropertyName);
                }
            }
        }

        private ObservableCollection<string> _Genres = null;

        /// <summary>
        /// Nom de la propriété Series
        /// </summary>

        public const string SeriesPropertyName = "Series";

        /// <summary>
        /// propriété Series :  
        /// </summary>

        public ObservableCollection<string> Series
        {
            get
            {
                return this._Series;
            }

            private set
            {
                if (this._Series != value)
                {
                    this._Series = value;
                    this.RaisePropertyChanged(SeriesPropertyName);
                }
            }
        }

        private ObservableCollection<string> _Series = null;

        /// <summary>
        /// Nom de la propriété SelectedGame
        /// </summary>

        public const string SelectedGamePropertyName = "SelectedGame";

        /// <summary>
        /// propriété SelectedGame :  
        /// </summary>

        public GameViewModel SelectedGame
        {
            get
            {
                return this._SelectedGame;
            }

            set
            {
                if (this._SelectedGame != value)
                {
                    this._SelectedGame = value;                    
                    this.RaisePropertyChanged(SelectedGamePropertyName);

                    this.HasSelectedGame = (value != null );
                }
            }
        }

        private GameViewModel _SelectedGame = null;

        
        /// <summary>
        /// Nom de la propriété HasSelectedGame
        /// </summary>

        public const string HasSelectedGamePropertyName = "HasSelectedGame";

        /// <summary>
        /// propriété HasSelectedGame :  
        /// </summary>

        public bool HasSelectedGame
        {
            get
            {
                return this._HasSelectedGame;
            }

            private set
            {
                if (this._HasSelectedGame != value)
                {
                    this._HasSelectedGame = value;
                    this.RaisePropertyChanged(HasSelectedGamePropertyName);
                }
            }
        }

        private bool _HasSelectedGame = false;

        /// <summary>
        /// Nom de la propriété Games
        /// </summary>

        public const string GamesPropertyName = "Games";

        /// <summary>
        /// propriété Games :  
        /// </summary>

        public ObservableCollection<GameViewModel> Games
        {
            get
            {
                return this._Games;
            }

            set
            {
                if (this._Games != value)
                {
                    this._Games = value;
                    this.RaisePropertyChanged(GamesPropertyName);

                    this.FilterGames();
                }
            }
        }

        private ObservableCollection<GameViewModel> _Games = null;
        
        /// <summary>
        /// Nom de la propriété Filter
        /// </summary>

        public const string FilterPropertyName = "Filter";

        /// <summary>
        /// propriété Filter :  
        /// </summary>

        public string Filter
        {
            get
            {
                return this._Filter;
            }

            set
            {
                if (this._Filter != value)
                {
                    this._Filter = value;
                    this.RaisePropertyChanged(FilterPropertyName);
                    this.FilterGames();
                }
            }
        }

        private string _Filter = null;

        /// <summary>
        /// Filter avec la propriété filter puis mettre dans GameFilter
        /// </summary>

        private void FilterGames()
        {
            if (this.Games == null)
            {
                return;
            }

            if (string.IsNullOrWhiteSpace(this.Filter) == true)
            {
                this.GamesFiltered = this.Games;
                return;
            }

            ObservableCollection<GameViewModel> newGames = new ObservableCollection<GameViewModel>();

            foreach (GameViewModel game in this.Games)
            {
                if (game.Label != null && game.Label.IndexOf(this.Filter.Trim(), StringComparison.InvariantCultureIgnoreCase) > -1)
                {
                    newGames.Add(game);
                }
            }

            this.GamesFiltered = newGames;
        }

        /// <summary>
        /// Nom de la propriété GameFiltered
        /// </summary>

        public const string GamesFilteredPropertyName = "GamesFiltered";

        /// <summary>
        /// propriété GameFiltered : 
        /// </summary>

        public ObservableCollection<GameViewModel> GamesFiltered
        {
            get
            {
                return this._GamesFiltered;
            }

            set
            {
                if (this._GamesFiltered != value)
                {
                    this._GamesFiltered = value;
                    this.RaisePropertyChanged(GamesFilteredPropertyName);
                }
            }
        }

        private ObservableCollection<GameViewModel> _GamesFiltered = null;

        /// <summary>
        /// Nouvelle liste
        /// </summary>

        public void New(string filename)
        {
            this.IsLoading = true;
            this.IsLoadedWithNoError = false;

            try
            {
                this.Games = new ObservableCollection<GameViewModel>();

                this.Series = new ObservableCollection<string>();

                this.GameListFullFilename = filename;

                this.EnsureDirectoryGameExists();
                this.CleanDirectoryGame();

                this.IsLoadedWithNoError = true;
            }
            finally
            {
                this.IsLoading = false;
            }
        }

        /// <summary>
        /// GameListFullFilenamePropertyName
        /// </summary>

        public const string GameListFullFilenamePropertyName = "GameListFullFilename";

        /// <summary>
        /// Obtenir le chemin complet vers la liste de jeu
        /// </summary>

        public string GameListFullFilename
        {
            get
            {
                return this.gameListFullFilename;
            }

            set
            {
                if( this.gameListFullFilename != value )
                {
                    this.gameListFullFilename = value;

                    if (value != null)
                    {
                        this.GameListPath = Path.GetDirectoryName(this.gameListFullFilename);
                    }
                    else
                    {
                        this.GameListPath = null;
                    }

                    this.RaisePropertyChanged(GameListFullFilenamePropertyName);
                }
            }
        }

        private string gameListFullFilename = null;

        /// <summary>
        /// Obtenir le chemin de la couverture
        /// </summary>

        public string CoversPath
        {
            get
            {
                return Path.Combine(this.GameListPath, "Covers");
            }
        }

        /// <summary>
        /// Obtenir le chemin de la couverture
        /// </summary>

        public string RomsPath
        {
            get
            {
                return Path.Combine(this.GameListPath, "Roms");
            }
        }

        /// <summary>
        /// être sur que les repertoire existe
        /// </summary>

        public void EnsureDirectoryGameExists()
        {
            try
            {
                Directory.CreateDirectory(this.CoversPath);
            }
            catch
            {
            }

            try
            {
                Directory.CreateDirectory(this.RomsPath);
            }
            catch
            {
            }
        }

        /// <summary>
        /// Détruire
        /// </summary>

        private void CleanDirectoryGame()
        {
            try
            {
                foreach (string file in Directory.GetFiles(this.CoversPath))
                {
                    File.Delete(file);
                }
            }
            catch
            {
            }

            try
            {
                foreach (string file in Directory.GetFiles(this.RomsPath))
                {
                    File.Delete(file);
                }
            }
            catch
            {
            }
        }


        /// <summary>
        /// Game
        /// </summary>

        public string GameListPath
        {
            get;
            private set;
        }

        
        /// <summary>
        /// Nom de la propriété IsLoading
        /// </summary>

        public const string IsLoadingPropertyName = "IsLoading";

        /// <summary>
        /// propriété IsLoading :  
        /// </summary>

        public bool IsLoading
        {
            get
            {
                return this._IsLoading;
            }

            set
            {
                if (this._IsLoading != value)
                {
                    this._IsLoading = value;
                    this.RaisePropertyChanged(IsLoadingPropertyName);
                }
            }
        }

        private bool _IsLoading = false;

        
        /// <summary>
        /// Nom de la propriété IsLoadedWithNoError
        /// </summary>

        public const string IsLoadedWithNoErrorPropertyName = "IsLoadedWithNoError";

        /// <summary>
        /// propriété IsLoadedWithNoError :  
        /// </summary>

        public bool IsLoadedWithNoError
        {
            get
            {
                return this._IsLoadedWithNoError;
            }

            set
            {
                if (this._IsLoadedWithNoError != value)
                {
                    this._IsLoadedWithNoError = value;
                    this.RaisePropertyChanged(IsLoadedWithNoErrorPropertyName);
                }
            }
        }

        private bool _IsLoadedWithNoError = false;        

        /// <summary>
        /// Chargement
        /// </summary>

        public void Load(string filename)
        {
            this.IsLoading = true;
            this.IsLoadedWithNoError = false;

            try
            {
                this.GameListFullFilename = filename;

                GameList gameList = new GameList();

                ObservableCollection<GameViewModel> result = new ObservableCollection<GameViewModel>();
                ObservableCollection<string> series = new ObservableCollection<string>();

                ObservableCollection<Game> games = gameList.Load(filename);

                foreach (Game game in games)
                {
                    // ajouter une série

                    if (string.IsNullOrWhiteSpace(game.Serie) == false)
                    {
                        if (series.Contains(game.Serie) == false)
                        {
                            series.Add(game.Serie);
                        }
                    }

                    result.Add(GameViewModel.Create(this, game));
                }

                this.Series = series;
                this.Games = result;

                this.IsLoadedWithNoError = true;
            }
            finally
            {
                this.IsLoading = false;
            }
        }

        /// <summary>
        /// Sauver la liste
        /// </summary>

        public void Save()
        {
            GameList gameList = new GameList();

            ObservableCollection<Game> games = new ObservableCollection<Game>();

            foreach (GameViewModel game in this.Games)
            {
                games.Add( game.Convert() );
            }

            gameList.Save(this.GameListFullFilename, games);
        }

        /// <summary>
        /// Ajouter une série
        /// </summary>
        /// <param name="serieName"></param>

        public bool AddSerie(string serieName)
        {
            if (string.IsNullOrWhiteSpace(serieName))
                return false;

            serieName = serieName.Trim();

            if (this.Series.Contains(serieName) == false)
            {
                this.Series.Add(serieName);
                return true;
            }

            return false;
        }

        /// <summary>
        /// Retirer une série
        /// </summary>
        /// <param name="serieName"></param>

        public void RemoveSerie(string serieName)
        {
            if( string.IsNullOrWhiteSpace( serieName ) )
                return;

            if (this.Series.Contains(serieName) == true)
            {
                this.Series.Remove(serieName);

                foreach (GameViewModel game in this.Games)
                {
                    if (game.Serie != null)
                    {
                        if (serieName.Trim().ToLower() == game.Serie.Trim().ToLower())
                        {
                            game.Serie = null;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Ajouter un jeu
        /// </summary>
        /// <param name="game"></param>

        public void AddGame(string machineName)
        {
            this.AddGame(this.CreateGame(machineName)); 
        }

        /// <summary>
        /// Ajouter un jeu
        /// </summary>

        public void AddGame(GameViewModel game)
        {
            if (this.Games != null)
            {
                if (game.Machine == null)
                {
                    throw new Exception("Game added must have a Machine name !");
                }

                // on nettoie le filtre pour voir le nouveau jeu
                this.Filter = "";

                Debug.Assert(game.GameListViewModel == this);

                this.Games.Add(game);
                this.SelectedGame = game;
            }
        }

        /// <summary>
        /// Creation d'un jeu
        /// </summary>

        public GameViewModel CreateGame(string machineName)
        {
            GameViewModel game = new GameViewModel(this);

            game.Machine = machineName;

            return game;
        }

        /// <summary>
        /// Retirer un jeu
        /// </summary>

        public void RemoveGame()
        {
            if (this.Games != null)
            {
                GameViewModel game = this.SelectedGame;

                if (game != null)
                {
                    int index = this.Games.IndexOf(game);

                    this.Games.Remove(game);
                    this.GamesFiltered.Remove(game);

                    if (index >= this.Games.Count)
                    {
                        index = this.Games.Count - 1;
                    }

                    if (index > -1)
                    {
                        this.SelectedGame = this.Games[index];
                    }
                }
            }
        }

        /// <summary>
        /// Retirer
        /// </summary>

        public void Remove()
        {
            if (this.Games != null)
            {
                this.Games = null;

                // Games

                try
                {
                    if (File.Exists(this.GameListFullFilename) == true)
                    {
                        File.Delete(this.GameListFullFilename);
                    }
                }
                catch
                {
                }

                // RomsPath

                try
                {
                    if (Directory.Exists(RomsPath) == true)
                    {
                        Directory.Delete(this.RomsPath);
                    }
                }
                catch
                {
                }

                // CoversPath

                try
                {
                    if (Directory.Exists(CoversPath) == true)
                    {
                        Directory.Delete(CoversPath);
                    }
                }
                catch
                {
                }
            }
            
            // destruction de la liste

            this.GameListFullFilename = null;            
        }
    }
}
